package com.huawang.mdesign.model.service.interceptor;

import com.huawang.business.exception.DisplayForm;
import com.huawang.mdesign.model.service.vo.BaseResponse;
import com.huawang.mdesign.model.service.config.MessageProcessor;
import com.huawang.business.constants.ErrorCode;
import com.huawang.business.exception.AbortExecutionException;
import com.huawang.core.semantics.exception.CommandException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.BindException;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.validation.*;
import java.util.Arrays;
import java.util.stream.Collectors;


@ControllerAdvice
@ResponseBody
@Slf4j
public class GlobalExceptionHandler {

    @Autowired
    private MessageProcessor messageProcessor;

    @ExceptionHandler(value = { BindException.class, ValidationException.class,
            MethodArgumentNotValidException.class })
    public BaseResponse<String> handleValidatedException(Exception e) {
        String resp;
        if (e instanceof MethodArgumentNotValidException) {
            MethodArgumentNotValidException ex = (MethodArgumentNotValidException) e;
            resp = ex.getBindingResult().getAllErrors().stream()
                    .map(ObjectError::getDefaultMessage)
                    .collect(Collectors.joining("; "));
            log.error("请求接口:{}.{}", ex.getParameter().getExecutable().getDeclaringClass(),
                    ex.getParameter().getExecutable().getName());
            log.error("请求参数错误:{}", resp);
        } else if (e instanceof ConstraintViolationException) {
            ConstraintViolationException ex = (ConstraintViolationException) e;
            resp = ex.getConstraintViolations().stream()
                    .map(ConstraintViolation::getMessage)
                    .collect(Collectors.joining("; "));
            log.error("请求参数错误:{}", resp);

        } else if (e instanceof BindException) {
            BindException ex = (BindException) e;
            resp = ex.getAllErrors().stream()
                    .map(ObjectError::getDefaultMessage)
                    .collect(Collectors.joining("; "));

        } else {
            resp = null;
        }

        return BaseResponse.error(ErrorCode.PARAM_ERROR.getCode(), resp);
    }

    @ExceptionHandler(ConstraintDeclarationException.class)
    public BaseResponse<String> constraintDeclarationException(ConstraintDeclarationException e) {
        log.error("execution ConstraintDeclarationException error【{}】", e.getMessage(), e);
        return BaseResponse.error(ErrorCode.CONSTRAINT_DECLARATION_EXCEPTION.getCode(), e.getMessage(), ErrorCode.CONSTRAINT_DECLARATION_EXCEPTION.getMessage());
    }

    @ExceptionHandler(UnexpectedTypeException.class)
    public BaseResponse<String> unexpectedTypeException(UnexpectedTypeException e) {
        log.error("execution unexpectedType error【{}】", e.getMessage(), e);
        return BaseResponse.error(ErrorCode.UNEXPECTED_TYPE_ERROR.getCode(), e.getMessage(), ErrorCode.UNEXPECTED_TYPE_ERROR.getMessage());
    }

    /**
     * 业务异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler(AbortExecutionException.class)
    public BaseResponse<String> abortExecutionException(AbortExecutionException e) {
        log.error("execution service error【{}:{}】", e.getCode(), e.getMessage(), e);
        if (e.getData() != null) {
            log.error("data:{}", e.getData());
        }
        // 异常内容生成:1.动态参数国际化 2.内容国际化
        DisplayForm messageForm = e.getMessageForm();
        String[] messageParams = messageForm.getParams() == null ? null : Arrays.stream(messageForm.getParams()).map(it -> {
            String key = String.valueOf(it);
            return messageProcessor.getMessage(key, null, key);
        }).toArray(String[]::new);
        String errorMsg = StringUtils.isEmpty(e.getMessage()) ? ErrorCode.SERVICE_ERROR.getMessage() :
                messageProcessor.getMessage(String.valueOf(e.getCode()),
                        messageParams,
                        messageForm.getContent());
        // 异常标题生成:1.动态参数国际化 2.标题国际化
        DisplayForm titleForm = e.getTitleForm();
        String[] titleParams = titleForm.getParams() == null ? null : Arrays.stream(titleForm.getParams()).map(it -> {
            String key = String.valueOf(it);
            return messageProcessor.getMessage(key, null, key);
        }).toArray(String[]::new);
        String errorTitle = messageProcessor.getMessage(e.getCode() + "_title",
                titleParams,
                titleForm.getContent());

        return BaseResponse.error(e.getCode(), errorTitle, errorMsg, e.getLevel());
    }

    /**
     * mof自定义异常
     *
     * @param e 异常
     * @return 异常结果
     */
    @ExceptionHandler(CommandException.class)
    public BaseResponse<String> handleBaseException(CommandException e) {
        log.error("CommandException service error【{}】", e.getMessage(), e);
        String errorMsg = StringUtils.isEmpty(e.getMessage()) ? ErrorCode.MOF_ERROR.getMessage() :
                messageProcessor.getMessage(String.valueOf(e.getCode()), null, e.getMessage());
        String errorTitle = messageProcessor.getMessage(e.getCode() + "_title", null, null);
        return BaseResponse.error(e.getCode(), errorTitle, errorMsg);
    }

    /**
     * 未知异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler(Exception.class)
    public BaseResponse<String> handleException(Exception e) {
        log.error(e.getMessage(), e);
        return BaseResponse.error(ErrorCode.SERVICE_ERROR.getCode(),
                messageProcessor.getMessage(String.valueOf(ErrorCode.SERVICE_ERROR.getCode()), null, e.getMessage()));
    }
}
